home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / Other Langs / MacPerl ƒ / Perl Source ƒ / MacPerl / MPMain.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-02  |  19.2 KB  |  936 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    MacPerl            -    Real Perl Application
  3. File        :    MPMain.c            -    The main event loop
  4. Author    :    Matthias Neeracher
  5.  
  6. A lot of this code is borrowed from 7Edit written by
  7. Apple Developer Support UK
  8.  
  9. Started    :    17Mar93                                Language    :    MPW C
  10. Modified    :    29May93    MN    Compiles correctly
  11.                 30May93    MN    Support Console Windows
  12.                 15Jul93    MN    Beginning to see the light
  13.                 16Aug93    MN    Moved scripting to separate file
  14.                 17Aug93    MN    Preferences
  15.                 17Oct93    MN    Mercutio Support
  16.                 12Dec93    MN    SacrificialGoat
  17.                 20Dec93    MN    Trying to be more subtle about cursors
  18.                 30Dec93    MN    DeferredKeys
  19. Last        :    30Dec93
  20. *********************************************************************/
  21.  
  22. #include <Memory.h>
  23. #include <QuickDraw.h>
  24. #include <Types.h>
  25. #include <Menus.h>
  26. #include <Windows.h>
  27. #include <Dialogs.h>
  28. #include <Traps.h>
  29. #include <Packages.h>
  30. #include <PPCToolbox.h>
  31. #include <Resources.h>
  32. #include <Editions.h>
  33. #include <Printing.h>
  34. #include <ToolUtils.h>
  35. #include <Desk.h>
  36. #include <Scrap.h>
  37. #include <OSEvents.h>
  38. #include <AppleEvents.h>
  39. #include <AEObjects.h>
  40. #include <Errors.h>
  41. #include <StandardFile.h>
  42. #include <Balloons.h>
  43. #include <String.h>
  44. #include <CType.h>
  45. #include <PLStringFuncs.h>
  46. #include <StdLib.h>
  47. #include <CursorCtl.h>
  48.  
  49. #include "MPGlobals.h"
  50. #include "MPUtils.h"
  51. #include "MPEditions.h"
  52. #include "MPAppleEvents.h"
  53. #include "MPWindow.h"
  54. #include "MPFile.h"
  55. #include "MPHelp.h"
  56. #include "MPScript.h"
  57. #include "MPUtils.h"
  58. #include "MPPreferences.h"
  59. #include "Mercutio.h"
  60.  
  61. #define RESOLVE_MAC_CONFLICTS
  62. #include <EXTERN.h>
  63. #include <perl.h>
  64.  
  65. #pragma segment Main
  66.  
  67. pascal void MaintainCursor(Boolean busy)
  68. {
  69.     Point         pt;
  70.     WindowPtr     wPtr;
  71.     GrafPtr       savePort;
  72.     DPtr          theDoc;
  73.     Boolean        inText = false;
  74.  
  75.     if (busy) {
  76.         SpinCursor(1);
  77.         
  78.         return;
  79.     }
  80.     
  81.     wPtr = FrontWindow();
  82.     if (Ours(wPtr)) {
  83.         theDoc = DPtrFromWindowPtr(wPtr);
  84.         GetPort(&savePort);
  85.         SetPort(wPtr);
  86.         GetMouse(&pt);
  87.         if (theDoc->theText)
  88.             if (inText = PtInRect(pt, &(**(theDoc->theText)).viewRect))
  89.                 SetCursor(&editCursor);
  90.             else
  91.                 SetCursor(&qd.arrow);
  92.         else
  93.             SetCursor(&qd.arrow);
  94.  
  95.         if (theDoc->theText)
  96.             TEIdle(theDoc->theText);
  97.  
  98. #ifndef RUNTIME
  99.         DoHelp(wPtr, theDoc, pt, inText);
  100. #endif
  101.  
  102.         SetPort(savePort);
  103.     }
  104. }
  105.  
  106. #pragma segment Main
  107.  
  108. pascal void MaintainMenus(void)
  109. {
  110.     DPtr               theDoc;
  111.     WindowPtr          firstWindow;
  112.     SectHandle         currSection;
  113.     static Boolean    mRunningPerl;
  114.  
  115.     firstWindow = FrontWindow();
  116.     if (!Ours(firstWindow)) {
  117.         EnableItem(myMenus[fileM], fmNew);
  118.         EnableItem(myMenus[fileM], fmOpen);
  119.         DisableItem(myMenus[fileM], fmClose);
  120.         DisableItem(myMenus[fileM], fmSave);
  121.         DisableItem(myMenus[fileM], fmSaveAs);
  122.         DisableItem(myMenus[fileM], fmRevert);
  123.         DisableItem(myMenus[fileM], fmPrint);
  124.         DisableItem(myMenus[fileM], fmPageSetUp);
  125.         EnableItem(myMenus[fileM], fmQuit);
  126.  
  127. #ifndef RUNTIME
  128.         DisableItem(myMenus[editM],  cPublisher);
  129.         DisableItem(myMenus[editM],  cSubscriber);
  130.         DisableItem(myMenus[editM],  cOptions);
  131.         DisableItem(myMenus[editM],  cBorders);
  132.  
  133.         EnableItem(myMenus[helpM], hmExplain);
  134. #endif 
  135.         
  136.         if (gRunningPerl != mRunningPerl)     {
  137.             if (gRunningPerl) 
  138.                 DeleteMenu(perlID);
  139.             else
  140.                 InsertMenu(myMenus[perlM], 0);
  141.             
  142.             mRunningPerl = gRunningPerl;
  143.             
  144.             DrawMenuBar();
  145.         }
  146.  
  147.         if (!mRunningPerl) {
  148.             SetItem(myMenus[perlM], pmRunFront, "\pRun Front Window");
  149.             DisableItem(myMenus[perlM], pmRunFront);
  150.         }
  151.         
  152.         EnableItem(myMenus[editM],  emPreferences);
  153.         
  154.         if (firstWindow) {
  155.             EnableItem(myMenus[editM], undoCommand);
  156.             EnableItem(myMenus[editM], cutCommand);
  157.             EnableItem(myMenus[editM], copyCommand);
  158.             EnableItem(myMenus[editM], pasteCommand);
  159.             EnableItem(myMenus[editM], clearCommand);
  160.         }
  161.     } else {
  162.         theDoc = DPtrFromWindowPtr(firstWindow);
  163.         
  164.         if (theDoc->kind == kDocumentWindow) {
  165.             EnableItem(myMenus[editM], pasteCommand);
  166. #ifndef RUNTIME
  167.             EnableItem(myMenus[editM], cBorders);
  168. #endif
  169.             if (!mRunningPerl) {
  170.                 Str255    title;
  171.                 
  172.                 PLstrcpy(title, "\pRun ");
  173.                 GetWTitle(firstWindow, title+5);
  174.                 title[0]             = title[5] + 6;
  175.                 title[5]              = '"';
  176.                 title[title[0]]    = '"';
  177.                 SetItem(myMenus[perlM], pmRunFront, title);
  178.                 EnableItem(myMenus[perlM], pmRunFront);
  179.             }
  180.         } else {
  181. #ifndef RUNTIME
  182.             DisableItem(myMenus[editM], cBorders);
  183. #endif
  184.             
  185.             if ((*theDoc->theText)->selStart < theDoc->u.cons.fence)
  186.                 DisableItem(myMenus[editM], pasteCommand);
  187.             else
  188.                 EnableItem(myMenus[editM], pasteCommand);
  189.  
  190.             if (!mRunningPerl) {
  191.                 SetItem(myMenus[perlM], pmRunFront, "\pRun Front Window");
  192.                 DisableItem(myMenus[perlM], pmRunFront);
  193.             }
  194.         }
  195.         
  196.         EnableItem(myMenus[fileM], fmClose);
  197.         EnableItem(myMenus[fileM], fmSave);
  198.         EnableItem(myMenus[fileM], fmSaveAs);
  199.         EnableItem(myMenus[fileM], fmPrint);
  200.         EnableItem(myMenus[fileM], fmPageSetUp);
  201.         EnableItem(myMenus[fileM], fmQuit);
  202.  
  203.         if (theDoc->kind == kDocumentWindow && theDoc->dirty)
  204.             EnableItem(myMenus[fileM], fmRevert);
  205.         else
  206.             DisableItem(myMenus[fileM], fmRevert);
  207.  
  208.         DisableItem(myMenus[editM], undoCommand);
  209.  
  210.         if (((**(theDoc->theText)).selEnd - (**(theDoc->theText)).selStart) < 0) {
  211.             DisableItem(myMenus[editM], cutCommand);
  212.             DisableItem(myMenus[editM], copyCommand);
  213.             DisableItem(myMenus[editM], clearCommand);
  214. #ifndef RUNTIME
  215.             DisableItem(myMenus[editM], cPublisher);
  216. #endif
  217.         } else {
  218.             EnableItem(myMenus[editM], cutCommand);
  219.             EnableItem(myMenus[editM], copyCommand);
  220.             EnableItem(myMenus[editM], clearCommand);
  221. #ifndef RUNTIME
  222.             EnableItem(myMenus[editM], cPublisher);
  223. #endif
  224.         }
  225.         
  226.         EnableItem(myMenus[editM],  emPreferences);
  227.  
  228. #ifndef RUNTIME
  229.         currSection =
  230.             GetSection(
  231.                 (**(theDoc->theText)).selStart,
  232.                 (**(theDoc->theText)).selEnd,
  233.                 theDoc);
  234.  
  235.         if (theDoc->kind != kDocumentWindow) {
  236.             DisableItem(myMenus[editM], cPublisher);
  237.             DisableItem(myMenus[editM], cSubscriber);
  238.             DisableItem(myMenus[editM], cOptions);
  239.         } else if (currSection) {
  240.             DisableItem(myMenus[editM], cPublisher);
  241.             DisableItem(myMenus[editM], cSubscriber);
  242.             EnableItem(myMenus[editM],  cOptions);
  243.             if ((**(**currSection).fSectHandle).kind == stPublisher)
  244.                 SetItem(myMenus[editM], cOptions, "\pPublisher Options…");
  245.             else
  246.                 SetItem(myMenus[editM], cOptions, "\pSubscriber Options…");
  247.         } else {
  248.             EnableItem(myMenus[editM],  cPublisher);
  249.             EnableItem(myMenus[editM],  cSubscriber);
  250.             DisableItem(myMenus[editM], cOptions);
  251.         }
  252.         
  253.         EnableItem(myMenus[helpM], hmExplain);
  254. #endif
  255.  
  256.         if (gRunningPerl != mRunningPerl)     {
  257.             if (gRunningPerl) 
  258.                 DeleteMenu(perlID);
  259.             else
  260.                 InsertMenu(myMenus[perlM], 0);
  261.             
  262.             mRunningPerl = gRunningPerl;
  263.             
  264.             DrawMenuBar();
  265.         }
  266.     }
  267. }
  268.  
  269. #pragma segment Main
  270.  
  271. pascal void SetUpCursors(void)
  272. {
  273.     CursHandle  hCurs;
  274.  
  275.     hCurs = GetCursor(1);
  276.     editCursor = **hCurs;
  277.     hCurs = GetCursor(watchCursor);
  278.     waitCursor = **hCurs;
  279. }
  280.  
  281. #pragma segment Main
  282.  
  283. pascal void SetUpMenus(void)
  284. {
  285.     short             i;
  286.     StringHandle    str;
  287.  
  288.     myMenus[appleM] = GetMenu(appleID);
  289.     AddResMenu(myMenus[appleM], 'DRVR');
  290.     myMenus[fileM] = GetMenu(fileID);
  291.     myMenus[editM] = GetMenu(editID);
  292.     myMenus[windowM]    = GetMenu(windowID);
  293.     myMenus[perlM]    = GetMenu(perlID);
  294.  
  295. #ifndef RUNTIME
  296.     for (i = appleM; i < kLastMenu; i++)
  297.         InsertMenu(myMenus[i], 0);
  298.  
  299.     HMGetHelpMenuHandle(&myMenus[helpM]);
  300.     str = GetString(helpID);
  301.     
  302.     HLock((Handle) str);
  303.     AppendMenu(myMenus[helpM], *str);
  304.     ReleaseResource((Handle) str);
  305. #else
  306.     for (i = appleM; i <= kLastMenu; i++)
  307.         InsertMenu(myMenus[i], 0);
  308. #endif
  309.     
  310.     SetShortMenus(); /* Does a DrawMenuBar() */
  311. }
  312.  
  313. pascal void DoFile(short theItem)
  314. {
  315.     short   alertResult;
  316.     DPtr    theDoc;
  317.     FSSpec  theFSSpec;
  318.     OSErr   fileErr;
  319.     TPrint  thePSetup;
  320.  
  321.     switch (theItem){
  322.     case fmNew:
  323.         IssueAENewWindow();
  324.         break;
  325.  
  326.     case fmOpen:
  327.         if (GetFile(&theFSSpec)==noErr)
  328.             fileErr = IssueAEOpenDoc(theFSSpec);
  329.         break;
  330.  
  331.     case fmClose:
  332.         IssueCloseCommand(FrontWindow());
  333.         break;
  334.  
  335.     case fmSave:
  336.     case fmSaveAs:
  337.         theDoc = DPtrFromWindowPtr(FrontWindow());
  338.  
  339.         if (theItem==fmSaveAs || theDoc->kind != kDocumentWindow || !theDoc->u.reg.everSaved) {
  340.             fileErr = GetFileNameToSaveAs(theDoc);
  341.             if (!fileErr)
  342.                 fileErr = IssueSaveCommand(theDoc->theWindow, &theDoc->theFSSpec);
  343.             else if (fileErr != userCanceledErr)    
  344.                 FileError("\perror saving ", theDoc->theFileName);
  345.  
  346.             if (fileErr == noErr)
  347.                 SetWTitle(theDoc->theWindow, theDoc->theFSSpec.name);
  348.         } else
  349.             fileErr = IssueSaveCommand(theDoc->theWindow, nil);
  350.         break;
  351.  
  352.     case fmRevert:
  353.         SetCursor(&qd.arrow);
  354.         theDoc = DPtrFromWindowPtr(FrontWindow());
  355.  
  356.         ParamText(theDoc->theFileName, "", "", "");
  357.         alertResult = Alert(RevertAlert, nil);
  358.         switch (alertResult){
  359.             case aaSave:
  360.                 if (IssueRevertCommand(theDoc->theWindow))
  361.                     FileError("\perror reverting ", theDoc->theFileName);
  362.         }
  363.         break;
  364.  
  365.     case fmPageSetUp:
  366.         theDoc = DPtrFromWindowPtr(FrontWindow());
  367.         if (DoPageSetup(theDoc)) {
  368.              thePSetup = **(theDoc->thePrintSetup);
  369.              IssuePageSetupWindow(theDoc->theWindow, thePSetup);
  370.          }
  371.         break;
  372.  
  373.     case fmPrint:
  374.         IssuePrintWindow(FrontWindow());
  375.          break;
  376.  
  377.     case fmQuit:
  378.         IssueQuitCommand();
  379.         break;
  380.     } /*of switch*/
  381. }
  382.  
  383. #pragma segment Main
  384.  
  385. pascal void DoCommand(long mResult)
  386. {
  387.     short   theItem;
  388.     short   err;
  389.     Str255  name;
  390.     DPtr    theDocument;
  391.  
  392.     theDocument = DPtrFromWindowPtr(FrontWindow());
  393.  
  394.     theItem = LoWord(mResult);
  395.  
  396.     switch (HiWord(mResult)) {
  397.     case appleID:
  398.         if (theItem == aboutItem) {
  399.             DoAbout();
  400.         } else {
  401.             GetItem(myMenus[appleM], theItem, name);
  402.             err = OpenDeskAcc(name);
  403.             SetPort(FrontWindow());
  404.         }
  405.           break;
  406.  
  407.     case fileID:
  408.         DoFile(theItem);
  409.         break;
  410.  
  411.     case editID:
  412.         SystemEdit(theItem - 1);
  413.  
  414.         switch (theItem) {
  415.         case cutCommand:
  416.             IssueCutCommand(theDocument);
  417.             break;
  418.  
  419.         case copyCommand:
  420.             IssueCopyCommand(theDocument);
  421.             break;
  422.  
  423.         case pasteCommand :
  424.             IssuePasteCommand(theDocument);
  425.             break;
  426.  
  427.         case clearCommand :
  428.             IssueClearCommand(theDocument);
  429.             break;
  430.  
  431.         case selectAllCommand:
  432.             if (theDocument)
  433.                 TESetSelect(0, (**(theDocument->theText)).teLength, theDocument->theText);
  434.             break;
  435.  
  436. #ifndef RUNTIME
  437.         case cPublisher:
  438.             IssueCreatePublisher(theDocument);
  439.             break;
  440.  
  441.         case cSubscriber:
  442.             DoSubscribe(theDocument);
  443.             break;
  444.  
  445.         case cOptions:
  446.             DoSectionOptions(theDocument);
  447.             break;
  448.  
  449.         case cBorders:
  450.             IssueShowBorders(theDocument->theWindow, !theDocument->u.reg.showBorders);
  451.             break;
  452. #endif
  453.  
  454.         case emFormat:
  455.             IssueFormatCommand(theDocument);
  456.             break;
  457.             
  458.         case emPreferences:
  459.             DoPrefDialog();
  460.             break;
  461.         }     /*of switch*/
  462.  
  463.         ShowSelect(theDocument);
  464.          break;
  465.     
  466.     case windowID:
  467.         DoSelectWindow(theItem);
  468.         break;
  469.  
  470.     case perlID:
  471.         DoScriptMenu(theItem);
  472.         break;
  473.  
  474. #ifndef RUNTIME    
  475.     case kHMHelpMenuID:
  476.         Explain(theDocument);
  477.         break;
  478. #endif
  479.     }                 /*of switch*/
  480.  
  481.     HiliteMenu(0);
  482. }
  483.  
  484. #pragma segment Main
  485.  
  486. pascal void DoMouseDown(EventRecord *myEvent)
  487. {
  488.     WindowPtr whichWindow;
  489.     Point     p;
  490.     Rect      dragRect;
  491.  
  492.     p = myEvent->where;
  493.     switch (FindWindow(p, &whichWindow)) {
  494.     case inDesk:
  495.         SysBeep(10);
  496.         break;
  497.  
  498.     case inGoAway:
  499.         if (Ours(whichWindow))
  500.             if (TrackGoAway(whichWindow, p))
  501.                 IssueCloseCommand(whichWindow);
  502.         break;
  503.  
  504.     case inMenuBar:
  505.         SetCursor(&qd.arrow);
  506.         SetupWindowMenu();
  507.         DoCommand(MenuSelect(p));
  508.         HiliteMenu(0);
  509.         break;
  510.  
  511.     case inSysWindow:
  512.         SystemClick(myEvent, whichWindow);
  513.         break;
  514.  
  515.     case inDrag:
  516.         dragRect = qd.screenBits.bounds;
  517.  
  518.         if (Ours(whichWindow)) {
  519.             DragWindow(whichWindow, p, &dragRect);
  520.             /*
  521.                 As rgnBBox may be passed by address
  522.             */
  523.             dragRect = (**((WindowPeek)whichWindow)->strucRgn).rgnBBox;
  524.             /*
  525.                 The windows already there, but still tell
  526.                 the our AppleEvents core about the move in case
  527.                 they want to do anything
  528.             */
  529.             IssueMoveWindow(whichWindow, dragRect);
  530.         }
  531.           break;
  532.  
  533.     case inGrow:
  534.         SetCursor(&qd.arrow);
  535.         if (Ours(whichWindow))
  536.             MyGrowWindow(whichWindow, p);
  537.         break;
  538.  
  539.     case inZoomIn:
  540.         DoZoom(whichWindow, inZoomIn, p);
  541.         break;
  542.  
  543.     case inZoomOut:
  544.         DoZoom(whichWindow, inZoomOut, p);
  545.         break;
  546.  
  547.     case inContent:
  548.         if (whichWindow != FrontWindow())
  549.             SelectWindow(whichWindow);
  550.         else
  551.             if (Ours(whichWindow))
  552.                 DoContent(whichWindow, myEvent);
  553.         break;
  554.     }                 /*of switch*/
  555. }
  556.  
  557. #pragma segment Main
  558.  
  559. pascal long GetSleep(void)
  560. {
  561.     long      sleep;
  562.     WindowPtr theWindow;
  563.     DPtr      theDoc;
  564.  
  565.     sleep = 0x7fffffff;
  566.     if (!gInBackground)
  567.         {
  568.             theWindow = FrontWindow();
  569.             if (theWindow)
  570.                 {
  571.                     theDoc = DPtrFromWindowPtr(theWindow);
  572.                     if ((**(theDoc->theText)).selStart == (**(theDoc->theText)).selEnd)
  573.                         sleep = GetCaretTime();
  574.                 }
  575.         }
  576.     return(sleep);
  577. }                     /*GetSleep*/
  578.  
  579. long FindMenuKey(EventRecord * ev)
  580. {
  581. #ifndef RUNTIME
  582.     /* Work around Help manager bug */
  583.     short    item    =    CountMItems(myMenus[helpM]);
  584.     short    key;
  585.     
  586.     GetItemCmd(myMenus[helpM], item, &key);
  587.     
  588.     if (toupper((char) key) == toupper(ev->message & charCodeMask))
  589.         return (kHMHelpMenuID << 16) | item;
  590.     else
  591. #endif
  592.         return PowerMenuKey(ev->message, ev->modifiers, myMenus[fileM]);
  593. }
  594.  
  595. #pragma segment Main
  596.  
  597. typedef enum {keyOK, keyRetry, keyAbort} KeyStatus;
  598.  
  599. KeyStatus TryKey(DPtr theDoc, char theChar)
  600. {
  601.     switch (theChar) {
  602.     case 0:
  603.     case 1:
  604.     case 2:
  605.     case 4:
  606.     case 5:
  607.     case 6:
  608.     case 7:
  609.     case 10:
  610.     case 11:
  611.     case 12:
  612.     case 14:
  613.     case 15:
  614.     case 16:
  615.     case 17:
  616.     case 18:
  617.     case 19:
  618.     case 20:
  619.     case 21:
  620.     case 22:
  621.     case 23:
  622.     case 24:
  623.     case 25:
  624.     case 26:
  625.     case 27:
  626.         return keyAbort;
  627.         break;
  628.     case ETX:
  629.         theChar = CR;
  630.         
  631.         break;
  632.     default:
  633.         break;
  634.     }
  635.  
  636. #ifndef RUNTIME
  637.     {
  638.         SectHandle  currSection;
  639.         
  640.         /*
  641.             don't allow a subscriber to be changed
  642.         */
  643.         currSection =
  644.             GetSection(
  645.                 (**(theDoc->theText)).selStart,
  646.                 (**(theDoc->theText)).selEnd,
  647.                 theDoc);
  648.     
  649.         if (currSection)
  650.             if ((**(**currSection).fSectHandle).kind == stSubscriber)
  651.                 if (!KeyOKinSubscriber(theChar))
  652.                     return keyAbort;
  653.     }
  654. #endif
  655.  
  656.     if (theDoc->kind == kDocumentWindow) {
  657. #ifndef RUNTIME                    
  658.         DoTEKeySectionRecalc(theDoc, theChar);
  659. #endif
  660.     } else if (theChar == BS) {
  661.         if (!AllSelected(theDoc->theText))
  662.             if ((*theDoc->theText)->selStart == (*theDoc->theText)->selEnd)
  663.                 if ((*theDoc->theText)->selStart-1 < theDoc->u.cons.fence)
  664.                     return keyAbort;
  665.                 else if ((*theDoc->theText)->selStart < theDoc->u.cons.fence)
  666.                     return keyAbort;
  667.     } else if (
  668.         (*theDoc->theText)->selStart < theDoc->u.cons.fence &&
  669.         !KeyOKinSubscriber(theChar)
  670.     ) 
  671.         return keyAbort;
  672.     else if (!theDoc->u.cons.selected)
  673.         return keyRetry;
  674.  
  675. #ifndef RUNTIME                    
  676.     AddKeyToTypingBuffer(theDoc, theChar);
  677. #endif
  678.  
  679.     TEKey(theChar, theDoc->theText);
  680.     EnforceMemory(theDoc, theDoc->theText);
  681.     AdjustScrollbars(theDoc, false);
  682.     ShowSelect(theDoc);
  683.  
  684.     theDoc->dirty = true;
  685.     
  686.     return keyOK;
  687. }
  688.  
  689. /* Our cursor/WaitNextEvent strategy */
  690.  
  691. #define BUSY_WAIT            120
  692. #define FRONT_FREQUENCY    30
  693. #define BACK_FREQUENCY  10
  694.  
  695. static long        lastNonBusy = 0;
  696. static long     lastWNE     = 0;
  697. static char        deferredKeys[256];
  698. static short    deferredRd;
  699. static short    deferredWr;
  700.  
  701. #pragma segment Main
  702.  
  703. pascal void MainEvent(Boolean busy)
  704. {
  705.     DPtr        theDoc;
  706.     char        theChar;
  707.     Boolean     activate;
  708.     WindowPtr   theWindow;
  709.     long            now;
  710.     EventRecord myEvent;
  711.  
  712.     if (!gSacrificialGoat)        /* Memory trouble */
  713.         if (gRunningPerl)            /* This script has gone too far */
  714.             fatal("Out of memory ! Aborting script for your own good...\n");
  715.         else                            /* We aborted it, now buy a new goat */
  716.             if (!(gSacrificialGoat = NewHandle(SACRIFICE)))
  717.                 exit(0);        /* Save our sorry ass. Shouldn't happen */
  718.     
  719.     now = TickCount();
  720.     if (busy) {
  721.         if (now - lastNonBusy < BUSY_WAIT)
  722.             busy = false;
  723.     } else
  724.         lastNonBusy = now;
  725.     
  726.     if (busy) {
  727.         MaintainCursor(busy);
  728.         
  729.         if (now - lastWNE < (gInBackground ? BACK_FREQUENCY : FRONT_FREQUENCY))
  730.             return;
  731.     } else {
  732.         MaintainCursor(busy);
  733.         MaintainMenus();
  734.     }
  735.     
  736.     lastWNE = now;    
  737.     gGotEof = nil;
  738.     
  739.     if (!gRunningPerl && GetHandleSize((Handle) gWaitingScripts)) {
  740.         AppleEvent * ev    =    (*gWaitingScripts)[0];
  741.         AppleEvent * repl    =    (*gWaitingScripts)[1];
  742.         
  743.         Munger((Handle) gWaitingScripts, 0, nil, 8, (Ptr) -1, 0);
  744.         
  745.         AEResumeTheCurrentEvent(
  746.             ev, repl, (EventHandlerProcPtr) kAEUseStandardDispatch, -1);
  747.     }
  748.     
  749.     if ((theDoc = DPtrFromWindowPtr(FrontWindow())) && theDoc->theText) 
  750.         while (deferredKeys[deferredRd]) {
  751.             switch (TryKey(theDoc, deferredKeys[deferredRd])) {
  752.             case keyOK:
  753.             case keyAbort:
  754.                 deferredKeys[deferredRd] = 0;
  755.                 deferredRd = (deferredRd + 1) & 255;
  756.                 continue;
  757.             }
  758.             break;
  759.         }
  760.  
  761.     if (WaitNextEvent(everyEvent, &myEvent, busy ? 0 : GetSleep(), nil))
  762.         switch (myEvent.what) {
  763.         case mouseDown:
  764. #ifndef RUNTIME
  765.             FlushAndRecordTypingBuffer();
  766. #endif
  767.             DoMouseDown(&myEvent);
  768.             lastNonBusy = now;
  769.             break;
  770.  
  771.         case keyDown:
  772.         case autoKey:
  773.             if (WeirdChar(&myEvent, cmdKey, ETX) 
  774.              || WeirdChar(&myEvent, controlKey, 'd')
  775.             )    {
  776.                  if (theDoc->kind != kDocumentWindow) {
  777.                     gGotEof            =    theDoc;
  778.                     theDoc->dirty     =     true;
  779.                 } 
  780.                 
  781.                 break;
  782.             } 
  783.             
  784.             theChar = myEvent.message & charCodeMask;
  785.  
  786.             if ((myEvent.modifiers & cmdKey) == cmdKey) {
  787.                 DoCommand(FindMenuKey(&myEvent));
  788.                 HiliteMenu(0);
  789.             } else if (theDoc && theDoc->theText)
  790.                 switch (TryKey(theDoc, theChar)) {
  791.                 case keyOK:
  792.                 case keyAbort:
  793.                     break;
  794.                 case keyRetry:
  795.                     deferredKeys[deferredWr] = theChar;
  796.                     deferredWr = (deferredWr + 1) & 255;
  797.                     break;
  798.                 }
  799.               break;
  800.  
  801.         case activateEvt:
  802.             activate = ((myEvent.modifiers & activeFlag) != 0);
  803.             theWindow = (WindowPtr)myEvent.message;
  804.             DoActivate(theWindow, activate);
  805.             break;
  806.  
  807.         case updateEvt:
  808.             theDoc = DPtrFromWindowPtr((WindowPtr)myEvent.message);
  809.             DoUpdate(theDoc);
  810.             break;
  811.  
  812.         case kHighLevelEvent:
  813. #ifndef RUNTIME
  814.             FlushAndRecordTypingBuffer();
  815. #endif
  816.             DoAppleEvent(myEvent);
  817.             break;
  818.  
  819.         case kOSEvent:
  820.             switch (myEvent.message & osEvtMessageMask) { /*high byte of message*/
  821.             case 0x01000000:
  822.                     gInBackground = ((myEvent.message & resumeFlag) == 0);
  823.                     if (!gInBackground)
  824.                         InitCursor();
  825.                     DoActivate(FrontWindow(), !gInBackground);
  826.             }
  827.         }
  828.         
  829.     if (gQuitting && gRunningPerl)
  830.         exit(0);
  831. }
  832.  
  833. pascal long VoodooChile(Size cbNeeded)
  834. {
  835.     long    oldA5 = SetCurrentA5();
  836.     long    res;
  837.     
  838.     if (gSacrificialGoat && (GZSaveHnd() != gSacrificialGoat)) {
  839.         /* Oh Memory Manager, our dark Lord. Take the blood of this animal to
  840.            unwield thy power to crush our enemies.
  841.             
  842.             (Chant 7 times)
  843.         */
  844.         DisposeHandle(gSacrificialGoat);
  845.         
  846.         gSacrificialGoat     =     0;
  847.         res                    =    SACRIFICE;
  848.     } else
  849.         res                     =    0;
  850.         
  851.     SetA5(oldA5);
  852.     
  853.     return res;
  854. }
  855.  
  856. #pragma segment Main
  857.  
  858. void main()
  859. {
  860.     OSErr  err;
  861.     short  result;
  862.  
  863.     InitGraf(&qd.thePort);
  864.     InitFonts();
  865.     FlushEvents(everyEvent, 0);
  866.     InitWindows();
  867.     InitMenus();
  868.     TEInit();
  869.     InitDialogs(nil);
  870.     InitCursor();
  871.  
  872.     MaxApplZone();
  873.     SetGrowZone(&VoodooChile);
  874.     SetUpCursors();
  875.  
  876.     /*check environment checks to see if we are running 7.0*/
  877.     if (!CheckEnvironment()) {
  878.         SetCursor(&qd.arrow);
  879.         /*pose the only 7.0 alert*/
  880.         result = Alert(302, nil);
  881.         return;
  882.     }
  883.  
  884.     OpenPreferences();
  885.     
  886.     SetUpMenus();
  887.  
  888.     gWCount                = 0;
  889.     gNewDocCount         = 0;
  890.     gQuitting              = false;
  891.     gFontMItem             = 0;
  892.     gConsoleList        = nil;
  893.     gActiveWindow        = nil;
  894.     gAppFile                = CurResFile();
  895.     gScriptFile            = gAppFile;
  896.     gWaitingScripts    = (AppleEvent ***) NewHandle(0);
  897.     gGotEof                = nil;
  898.     gSacrificialGoat    = NewHandle(SACRIFICE);
  899.  
  900. #ifndef RUNTIME
  901.     if (err = InitEditionPack()) {
  902.         ShowError("\pInitEditionPack", err);
  903.         gQuitting = true;
  904.     }
  905.  
  906.     if (err = AEObjectInit()) {
  907.         ShowError("\pAEObjectInit", err);
  908.         gQuitting = true;
  909.     }
  910.  
  911.     InitAppleEvents();
  912.  
  913.     if (err = PPCInit()) {
  914.         ShowError("\pPPCInit", err);
  915.         gQuitting = true;
  916.     }
  917. #else
  918.     if (gAppleEventsImplemented) {
  919.         InitAppleEvents();
  920.         
  921.         if (err = PPCInit()) {
  922.             ShowError("\pPPCInit", err);
  923.             gQuitting = true;
  924.         }
  925.     }
  926. #endif
  927.     
  928.     if (gQuitting)
  929.         exit(0);
  930.         
  931.     InitPerlEnviron();
  932.     
  933.     for (gQuitting = DoRuntime(); !gQuitting; )
  934.         MainEvent(false);
  935. }
  936.